package com.xique.park.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xique.common.core.domain.R;
import com.xique.common.core.web.domain.PageResult;
import com.xique.park.bean.domain.RefundOrder;
import com.xique.park.bean.dto.RefundOrderExportDto;
import com.xique.park.bean.request.web.refund.RefundOrderRequest;
import com.xique.park.constant.ExcelConstant;
import com.xique.park.mapper.RefundOrderMapper;
import com.xique.park.service.service.IRefundOrderService;
import com.xique.system.api.RemoteSystemUserService;
import com.xique.system.api.dto.OperateDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 退款记录服务实现
 *
 * @author WLD
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class RefundOrderServiceImpl extends ServiceImpl<RefundOrderMapper, RefundOrder> implements IRefundOrderService {

    private final RemoteSystemUserService remoteSystemUserService;

    private final RefundOrderMapper refundOrderMapper;

    @Override
    public PageResult selectPageList(RefundOrderRequest request) {
        // 分页查询
        IPage<RefundOrder> pageList = selectPage(request);

        List<RefundOrder> refundOrderList = pageList.getRecords();
        if (CollUtil.isEmpty(refundOrderList)) {
            return PageResult.getEmptyInstance(request.getPageNum(), request.getPageSize());
        }

        // 赋值操作人信息
        getUpdateByInfo(refundOrderList);

        // 退款统计信息
        long num = 0;
        long successNum = 0;
        BigDecimal totalRefundAmount = new BigDecimal("0");
        RefundOrder refundOrder = selectStatisticalInfo(request);
        if (null != refundOrder) {
            num = refundOrder.getNum();
            successNum = refundOrder.getSuccessNum();
            totalRefundAmount = refundOrder.getTotalRefundAmount();
        }

        return PageResult
                .builder()
                .pageNum(request.getPageNum())
                .pageSize(request.getPageSize())
                .totalPages(pageList.getPages())
                .totalSize(pageList.getTotal())
                .list(refundOrderList)
                .num(num)
                .successNum(successNum)
                .totalRefundAmount(totalRefundAmount)
                .build();
    }

    private RefundOrder selectStatisticalInfo(RefundOrderRequest request) {
        return refundOrderMapper.selectStatisticalInfo(request);
    }

    @Override
    public void export(RefundOrderRequest request, HttpServletResponse response) {
        // 导出的记录总数
        long totalSize = getCount(request);
        if (totalSize > 0) {
            long totalPages = totalSize / ExcelConstant.PER_WRITE_ROW_COUNT + 1;
            log.info("[退款记录]-excel导出，请求参数：{}，总条数：{}，总页数：{}，每页数量：{}", request, totalSize, totalPages, ExcelConstant.PER_WRITE_ROW_COUNT);

            ExcelWriter excelWriter = null;
            try {
                String fileName = URLEncoder.encode("退款记录.xlsx", "UTF-8");

                response.setCharacterEncoding("UTF-8");
                response.setHeader("Content-disposition", "attachment; filename=" + fileName);
                response.setContentType("application/x-xls");

                OutputStream out = response.getOutputStream();
                excelWriter = EasyExcelFactory.write(out, RefundOrderExportDto.class).build();

                for (int pageNum = 1; pageNum <= totalPages; pageNum++) {
                    long startTime = System.currentTimeMillis();

                    log.info("[退款记录]-excel导出,开始到导出第{}页", pageNum);

                    // 分页查询结算记录
                    request.setPageNum(pageNum);
                    request.setPageSize(ExcelConstant.PER_WRITE_ROW_COUNT);
                    IPage<RefundOrderExportDto> refundOrderPage = selectExportPage(request);
                    List<RefundOrderExportDto> refundOrderList = refundOrderPage.getRecords();

                    // 导出
                    WriteSheet writeSheet = EasyExcelFactory.writerSheet(pageNum, "退款记录" + pageNum).build();
                    excelWriter.write(refundOrderList, writeSheet);

                    log.info("[退款记录]-excel导出,第{}页到导出完成，耗时：{}", pageNum, System.currentTimeMillis() - startTime);
                }
            } catch (UnsupportedEncodingException e) {
                log.error("[退款记录]-excel导出，编码格式错误");
                e.printStackTrace();
            } catch (IOException e) {
                log.error("[退款记录]-excel导出，IO异常");
                e.printStackTrace();
            } finally {
                if (excelWriter != null) {
                    excelWriter.finish();
                }
            }
        }
    }

    @Override
    public List<RefundOrder> selectList(RefundOrder refundOrder) {
        LambdaQueryWrapper<RefundOrder> queryWrapper = getQueryWrapper(refundOrder);
        return list(queryWrapper);
    }

    private IPage<RefundOrderExportDto> selectExportPage(RefundOrderRequest request) {
        Page<RefundOrderExportDto> page = new Page<>();
        page.setCurrent(request.getPageNum());
        page.setSize(request.getPageSize());
        return baseMapper.selectExportPage(page, request);
    }

    private long getCount(RefundOrderRequest request) {
        LambdaQueryWrapper<RefundOrder> queryWrapper = getQueryWrapper(request);
        return count(queryWrapper);
    }

    private IPage<RefundOrder> selectPage(RefundOrderRequest request) {
        LambdaQueryWrapper<RefundOrder> queryWrapper = getQueryWrapper(request);

        // 分页
        Page<RefundOrder> pageRequest = new Page<>();
        pageRequest.setCurrent(request.getPageNum());
        pageRequest.setSize(request.getPageSize());

        return page(pageRequest, queryWrapper);
    }

    private LambdaQueryWrapper<RefundOrder> getQueryWrapper(RefundOrder refundOrder) {
        LambdaQueryWrapper<RefundOrder> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.eq(null != refundOrder.getParkId(), RefundOrder::getParkId, refundOrder.getParkId());
        queryWrapper.eq(StrUtil.isNotBlank(refundOrder.getOrderNo()), RefundOrder::getOrderNo, refundOrder.getOrderNo());

        // 排序
        queryWrapper.orderByDesc(RefundOrder::getApplyTime);

        return queryWrapper;
    }

    private LambdaQueryWrapper<RefundOrder> getQueryWrapper(RefundOrderRequest request) {
        LambdaQueryWrapper<RefundOrder> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.eq(null != request.getParkId(), RefundOrder::getParkId, request.getParkId());
        queryWrapper.like(StrUtil.isNotBlank(request.getPlate()), RefundOrder::getPlate, request.getPlate());
        queryWrapper.eq(StrUtil.isNotBlank(request.getOrderNo()), RefundOrder::getOrderNo, request.getOrderNo());
        queryWrapper.eq(StrUtil.isNotBlank(request.getPaySsn()), RefundOrder::getPaySsn, request.getPaySsn());
        queryWrapper.eq(StrUtil.isNotBlank(request.getRefundId()), RefundOrder::getRefundId, request.getRefundId());
        queryWrapper.eq(StrUtil.isNotBlank(request.getIcbcRefundId()), RefundOrder::getIcbcRefundId, request.getIcbcRefundId());
        queryWrapper.eq(StrUtil.isNotBlank(request.getRefundStatus()), RefundOrder::getRefundStatus, request.getRefundStatus());

        queryWrapper.ge(StrUtil.isNotBlank(request.getApplyTimeStart()), RefundOrder::getApplyTime, request.getApplyTimeStart());
        queryWrapper.le(StrUtil.isNotBlank(request.getApplyTimeEnd()), RefundOrder::getApplyTime, request.getApplyTimeEnd());

        // 排序
        queryWrapper.orderByDesc(RefundOrder::getApplyTime);

        return queryWrapper;
    }

    private void getUpdateByInfo(List<RefundOrder> refundOrderList) {
        if (CollUtil.isNotEmpty(refundOrderList)) {
            StringBuilder operateIds = new StringBuilder();
            refundOrderList.forEach(refundOrder -> {
                Long operateId = refundOrder.getCreateUser();
                if (null != operateId) {
                    operateIds.append(operateId).append(",");
                }
            });

            if (StrUtil.isNotBlank(operateIds)) {
                R<List<OperateDTO>> updateUserResult = remoteSystemUserService.getOperateList(operateIds.toString());
                if (null != updateUserResult.getData()) {
                    List<OperateDTO> operateDTOList = updateUserResult.getData();
                    if (CollUtil.isNotEmpty(operateDTOList)) {
                        Map<Long, String> operateMap = operateDTOList.stream().collect(Collectors.toMap(OperateDTO::getOperateId, OperateDTO::getOperateName));
                        refundOrderList.forEach(refundOrder -> refundOrder.setUpdateBy(operateMap.get(refundOrder.getCreateUser())));
                    }
                }
            }
        }
    }

}
